﻿using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Claims;
using ApiLib.AppStart;
using ApiLib.Common.Attributes.IocAttributes;
using ApiLib.Common.Attributes.TaskAttributes;
using Furion;
using Furion.Logging;
using Furion.Schedule;
using Furion.TaskQueue;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;

namespace ApiLib.Utils;

/// <summary>
/// 
/// </summary>
public static class WebUtil
{
    /// <summary>
    /// 初始化Furion
    /// </summary>
    /// <returns></returns>
    public static bool InitApp => GlobalConfig.AppCoreConfig != null;

    /// <summary>
    /// 获取用户信息
    /// </summary>
    /// <returns></returns>
    public static string GetSid()
    {
        return App.User.FindFirstValue(ClaimTypes.Sid) ?? "";
    }

    /// <summary>
    /// 是否Linux操作系统
    /// </summary>
    public static bool IsLinuxOs => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);

    /// <summary>
    /// 是否Windows操作系统
    /// </summary>
    public static bool IsWindowsOs => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

    /// <summary>
    /// 获取本地Url地址
    /// </summary>
    /// <returns></returns>
    public static ICollection<string>? Addresses()
    {
        var feature = App.GetService<IServer>().Features.Get<IServerAddressesFeature>();
        return feature?.Addresses ?? default;
    }
    
    /// <summary>
    /// 是否使用JWT
    /// </summary>
    // public static bool UseJwt => App.GetConfig<Dictionary<string, string>>("JWTSettings") != null;
    // public static bool UseJwt => App.GetConfig<object>("JWTSettings") != null;
    public static bool UseJwt => App.Configuration.Exists("JWTSettings");

    #region 日志

    /// <summary>
    /// 自定义打印日志
    /// </summary>
    /// <param name="message"></param>
    public static void LogError(this string message)
    {
        if (MongoUtil.UseMongo)
        {
            MongoUtil.LogExp(message);
        }

        if (InitApp)
        {
            Log.Error(message);
        }
    }

    /// <summary>
    /// 自定义打印日志
    /// </summary>
    /// <param name="message"></param>
    /// <param name="type"></param>
    private static void LogInformation(this string message, LogType type = LogType.Normal)
    {
        if (MongoUtil.UseMongo)
        {
            MongoUtil.Log(message, type);
        }

        if (InitApp)
        {
            Log.Information(message);
        }
        else
        {
            Console.WriteLine(message);
        }
    }

    /// <summary>
    /// 普通日志
    /// </summary>
    /// <param name="message"></param>
    public static void LogInfo(string message)
    {
        message.LogInformation();
    }

    /// <summary>
    /// 系统日志
    /// </summary>
    /// <param name="message"></param>
    public static void LogSys(string message)
    {
        message.LogInformation(LogType.Sys);
    }

    /// <summary>
    /// 数据库日志
    /// </summary>
    /// <param name="message"></param>
    public static void LogSql(string message)
    {
        message.LogInformation(LogType.Sql);
    }

    /// <summary>
    /// 异常日志
    /// </summary>
    /// <param name="message"></param>
    public static void LogExp(string message)
    {
        message.LogError();
    }

    /// <summary>
    /// 异常日志
    /// </summary>
    /// <param name="message"></param>
    /// <param name="e"></param>
    public static void LogExp(string message, Exception e)
    {
        Error(message, e);
        // message.LogError();
    }

    /// <summary>
    /// 请求日志
    /// </summary>
    /// <param name="message"></param>
    public static void LogReq(string message)
    {
        message.LogInformation(LogType.Req);
    }

    /// <summary>
    /// 自定义打印日志
    /// </summary>
    /// <param name="message"></param>
    public static void Error(string message)
    {
        message.LogError();
    }

    /// <summary>
    /// 自定义打印日志
    /// </summary>
    /// <param name="message"></param>
    /// <param name="e">异常</param>
    public static void Error(string message, Exception e)
    {
        $"{message}\r\n异常：{e.GetType().Name}=>{e.Message}".LogError();
    }

    /// <summary>
    /// 自定义打印日志
    /// </summary>
    /// <param name="message"></param>
    public static void Information(string message)
    {
        message.LogInformation();
    }

    #endregion

    #region IOC

    /// <summary>
    /// 组件
    /// </summary>
    public static readonly List<Type> Components = [];

    /// <summary>
    /// 扫描组件
    /// </summary>
    public static void ScanComponents()
    {
        Components.Clear();
        AssemblyUtil.ScanAllTypes(type =>
        {
            if (type.IsAssignableTo(typeof(ControllerBase)) ||
                type.GetCustomAttribute(typeof(ComponentAttribute)) is ComponentAttribute)
            {
                Components.Add(type);
            }
        });
    }
    
    
    /// <summary>
    /// 后续配置
    /// </summary>
    public static void LoadSchedule()
    {
        foreach (var type in Components)
        {
            //todo 自动注入，目前只能在控制器或动态 WebAPI 中使用
            /*var properties = type.GetProperties();
            foreach (var info in properties)
            {
                if (info.GetCustomAttribute(typeof(AutowiredAttribute)) is AutowiredAttribute autowired)
                {
                    TypeDescriptor.AddAttributes(info, new FromServicesAttribute());
                }
            }
            var properties2 = type.GetProperties(BindingFlags.NonPublic|BindingFlags.Instance);
            foreach (var info in properties2)
            {
                if (info.GetCustomAttribute(typeof(AutowiredAttribute)) is AutowiredAttribute autowired)
                {
                    TypeDescriptor.AddAttributes(info, new FromServicesAttribute());
                }
            }*/

            //扫描方法
            var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
            var methodInfos2 = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
            foreach (var info in methodInfos)
            {
                LoadScheduleMethod(info);
            }
            foreach (var info in methodInfos2)
            {
                LoadScheduleMethod(info);
            }
        }
    }

    private static void LoadScheduleMethod(MethodInfo methodInfo)
    {
        if (methodInfo.GetCustomAttribute(typeof(ScheduleOnceAttribute)) is ScheduleOnceAttribute scheduleOnce)
        {
            WebUtil.AddTaskOnce(methodInfo,scheduleOnce);
        }
        else if (methodInfo.GetCustomAttribute(typeof(ScheduleAttribute)) is ScheduleAttribute schedule)
        {
            WebUtil.AddTask(methodInfo,schedule);
        }
    }

    #endregion

    #region 任务

    /// <summary>
    /// 添加任务
    /// </summary>
    /// <param name="methodInfo"></param>
    /// <param name="schedule"></param>
    public static void AddTask(MethodInfo methodInfo, ScheduleAttribute schedule)
    {
        var builder = !string.IsNullOrEmpty(schedule.Cron)
            ? TriggerBuilder.Cron(schedule.Cron, schedule.Format)
            : schedule.Interval > 0
                ? TriggerBuilder.Period(schedule.Interval)
                : default;
        if (builder == null) return;
        var factory = App.GetService<ISchedulerFactory>();
        factory.AddJob((context, token) =>
        {
            try
            {
                AssemblyUtil.RunMethod(methodInfo);
            }
            catch (Exception e)
            {
                WebUtil.LogExp($"执行定时任务{methodInfo.Name}异常", e);
            }

            return Task.CompletedTask;
        }, schedule.Concurrent, builder);
    }

    /// <summary>
    /// 添加单次任务
    /// </summary>
    /// <param name="methodInfo"></param>
    /// <param name="schedule"></param>
    public static void AddTaskOnce(MethodInfo methodInfo, ScheduleOnceAttribute schedule)
    {
        TaskQueued.Enqueue(provider =>
        {
            try
            {
                AssemblyUtil.RunMethod(methodInfo);
            }
            catch (Exception e)
            {
                WebUtil.LogExp($"执行定时任务{methodInfo.Name}异常", e);
            }
        }, schedule.Delay);
    }

    #endregion
}